package com.sky.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.AddressBook;
import com.sky.entity.OrderDetail;
import com.sky.entity.Orders;
import com.sky.entity.ShoppingCart;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.AddressBookMapper;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.ShoppingCartMapper;
import com.sky.result.PageResult;
import com.sky.service.OrdersService;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrdersHistoryVO;
import com.sky.vo.OrdersSearchVO;
import com.sky.websocket.WebSocketServer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class OrdersServiceImpl implements OrdersService {
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 用户提交订单
     * @param ordersSubmitDTO 订单信息
     * @return 返回信息
     * 业务分析:
     *      1.先判断有没有地址信息,没有抛异常
     *      2.在判断有没有商品信息,没有抛异常
     *      3.保存订单信息到订单表
     *      4.保存订单详情到订单详情表
     *      5.返回前端需要的数据
     */
    @Transactional
    @Override
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {
        //1.先判断有没有地址信息,没有抛异常
        AddressBook addressBook = addressBookMapper.findById(ordersSubmitDTO.getAddressBookId());
        if (addressBook == null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
        //2.在判断有没有商品信息,没有抛异常
        Long userId = BaseContext.getCurrentId();
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.findByUserId(userId);
        if (shoppingCartList == null || shoppingCartList.size() == 0){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //3.保存订单信息到订单表
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        //生成订单号
        orders.setNumber(System.currentTimeMillis() + "" + userId);
        //设置状态为带付款
        orders.setStatus(Orders.PENDING_PAYMENT);
        //设置下单用户
        orders.setUserId(userId);
        //设置下单时间
        orders.setOrderTime(LocalDateTime.now());
        //设置支付状态
        orders.setPayStatus(Orders.UN_PAID);
        //设置手机号
        orders.setPhone(addressBook.getPhone());
        //拼接地址信息
        orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())
                + (addressBook.getCityName() == null ? "" : addressBook.getCityName())
                + (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())
                + (addressBook.getDetail() == null ? "" : addressBook.getDetail()));
        //设置收货人
        orders.setConsignee(addressBook.getConsignee());
        //3.保存订单信息到订单表,并且返回主键
        ordersMapper.add(orders);
        //4.保存订单详情到订单详情表
        shoppingCartList.forEach(shoppingCart->{
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(shoppingCart,orderDetail);
            //这里需要把复制过来的id清掉
            orderDetail.setId(null);
            //设置订单返回的主键id
            orderDetail.setOrderId(orders.getId());
            //把订单详情保存到表中
            orderDetailMapper.add(orderDetail);
        });
        //5.返回前端需要的数据
        return OrderSubmitVO.builder()
                .orderAmount(orders.getAmount())
                .orderNumber(orders.getNumber())
                .orderTime(orders.getOrderTime())
                .id(orders.getId())
                .build();
    }

    /**
     * 支付成功会修改订单
     * @param orderNum
     */
    @Override
    public void paySuccess(String orderNum) {
        //根据订单号查询订单
        Orders orders = ordersMapper.findByOrderNum(orderNum);
        Orders paidOrders = Orders.builder()
                .id(orders.getId())
                //支付状态给成已支付
                .payStatus(Orders.PAID)
                //订单状态改成待接单
                .status(Orders.TO_BE_CONFIRMED)
                //设置支付时间
                .checkoutTime(LocalDateTime.now())
                .build();
        //更新订单消息
        ordersMapper.update(paidOrders);
        //拿到组装的数据json字符串
        String jsonStr = createWebSocketParams(1,orders.getId(),orders.getNumber());
        //发送消息
        webSocketServer.sendToAllClient(jsonStr);

    }

    /**
     * 查询历史订单
     * @param ordersPageQueryDTO
     * @return
     */
    @Override
    public PageResult historyOrders(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
        Long userId = BaseContext.getCurrentId();
        //根据userId和状态查询订单
        List<Orders> list = ordersMapper.searchHistory(ordersPageQueryDTO.getStatus(),userId);
        PageInfo<Orders> pageInfo = new PageInfo<>(list);
        List<OrdersHistoryVO> voList = list.stream().map(orders -> {
            //根据订单号查询商品详情
            List<OrderDetail> orderDetailList = orderDetailMapper.findByOrderId(orders.getId());
            OrdersHistoryVO ordersHistoryVO = new OrdersHistoryVO();
            BeanUtils.copyProperties(orders, ordersHistoryVO);
            ordersHistoryVO.setOrderDetailList(orderDetailList);
            return ordersHistoryVO;
        }).collect(Collectors.toList());
        return new PageResult(pageInfo.getTotal(),voList);
    }


    /**
     * 再来一单
     * @param id 订单id
     * 业务分析:
     *    1.根据订单id查询订单详情
     *    2.将订单详情里的菜品加到购物车
     *
     */
    @Override
    public void repetition(Long id) {
        List<OrderDetail> orderDetailList = orderDetailMapper.findByOrderId(id);
        orderDetailList.forEach(orderDetail->{
            //将查到的商品加到购物车里
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtils.copyProperties(orderDetail,shoppingCart);
            Long userId = BaseContext.getCurrentId();
            //这里记得要设置用户id
            shoppingCart.setUserId(userId);
            //重置id
            shoppingCart.setId(null);
            shoppingCartMapper.add(shoppingCart);
        });
    }

    /**
     * 查看订单详情
     * @param id
     * @return
     */
    @Override
    public OrdersHistoryVO orderDetail(Long id) {
        if (id == null){
            throw new OrderBusinessException(MessageConstant.PARAM_ERROR);
        }
        //先查询订单
        Orders orders = ordersMapper.findById(id);
        //在查询订单详情
        List<OrderDetail> orderDetailList = orderDetailMapper.findByOrderId(id);
        OrdersHistoryVO ordersHistoryVO = new OrdersHistoryVO();
        BeanUtils.copyProperties(orders,ordersHistoryVO);
        ordersHistoryVO.setOrderDetailList(orderDetailList);
        return ordersHistoryVO;
    }

    /**
     * 用户支付
     * @param ordersPaymentDTO
     * 业务分析:
     * 1.先根据订单号查询订单信息
     * 2.整合订单信息,发送给微信端,拿到预订单
     * 3.整合预订单信息发送给小程序,让用户完成支付
     * 4.支付完成后要清空购物车
     *
     */
    @Override
    public void payment(OrdersPaymentDTO ordersPaymentDTO) {
        //先根据订单号查询订单信息
        Orders orders = ordersMapper.findByOrderNum(ordersPaymentDTO.getOrderNumber());
        //2.3步无法完成,只能模拟一下
        //4.清空购物车
        Long userId = BaseContext.getCurrentId();
        shoppingCartMapper.delByUserId(userId);
    }

    /**
     * 催单
     * @param id
     */
    @Override
    public void reminder(Long id) {
        Orders orders = ordersMapper.findById(id);
        //拿到组装的数据json字符串
        String jsonStr = createWebSocketParams(2,orders.getId(),orders.getNumber());
        //发送消息
        webSocketServer.sendToAllClient(jsonStr);
    }

    /**
     * 返回前段消息的数据组装
     * @param type
     * @param orderId
     * @param orderNumber
     * @return
     */
    private String createWebSocketParams(Integer type,Long orderId,String orderNumber){
        HashMap<String, Object> params = new HashMap<>();
        //数据组装,type:1来单提醒
        params.put("type",type);
        //订单id
        params.put("orderId",orderId);
        //提示信息,返回订单号
        params.put("content","订单号: " + orderNumber);
        //Map对象转化成json字符串并返回
        return JSONObject.toJSONString(params);
    }

    /**
     * 取消订单
     * @param id
     * 业务分析:
     * 1.先根据id查询订单
     * 2.将订单信息发给微信端,通知微信退款
     * 3.订单状态改为取消
     */
    @Override
    public void cancel(Long id) {
        //如果传过来的是null,直接抛出业务异常
        if (id == null){
            throw new OrderBusinessException(MessageConstant.USER_CANNOT_CANCEL_ORDER);
        }
        Orders orders = ordersMapper.findById(id);
        //如果上架已接单或者在派送中,用户无法自己取消,要联系商家取消
        if (orders.getStatus() == Orders.CONFIRMED || orders.getStatus() == Orders.DELIVERY_IN_PROGRESS){
            throw new OrderBusinessException(MessageConstant.USER_CANNOT_CANCEL_ORDER);
        }
        if(orders.getPayStatus() == Orders.PAID){
            /*如果已经付款,这里要通知微信退款 */
        }
        Orders cancel = Orders.builder()
                .id(id)
                .status(Orders.CANCELLED)
                .cancelTime(LocalDateTime.now())
                .cancelReason(MessageConstant.USER_CANCEL_ORDER)
                .build();
        ordersMapper.update(cancel);
    }

    /**
     * 退款成功
     * @param orderNum
     */
    @Override
    public void refundSuccess(String orderNum) {
        //退款成功之后要把订单支付状态改成退款
        Orders orders = ordersMapper.findByOrderNum(orderNum);
        Orders refund = Orders.builder()
                .payStatus(Orders.REFUND)
                .id(orders.getId())
                .build();
        ordersMapper.update(refund);
    }

    /**
     * 管理端查询订单
     * @param ordersPageQueryDTO
     * @return
     * 根据前端需求查询订单信息后,将订单详情中的菜品信息做字符串拼接
     */
    @Override
    public PageResult search(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(),ordersPageQueryDTO.getPageSize());
        //查询订单
        List<Orders> list = ordersMapper.search(ordersPageQueryDTO);
        PageInfo<Orders> pageInfo = new PageInfo<>(list);
        List<OrdersSearchVO> voList = list.stream().map(orders -> {
            OrdersSearchVO ordersSearchVO = new OrdersSearchVO();
            BeanUtils.copyProperties(orders, ordersSearchVO);
            List<OrderDetail> orderDetails = orderDetailMapper.findByOrderId(orders.getId());
            String allDish = "";
            for (int i = 0; i < orderDetails.size(); i++) {
                //拼接菜品字符串
                String dish = orderDetails.get(i).getName();
                if (i == orderDetails.size() -1){
                    allDish += dish;
                }else {
                    allDish += dish + "，";
                }
            }
            ordersSearchVO.setOrderDishes(allDish);
            return ordersSearchVO;
        }).collect(Collectors.toList());
        return new PageResult(pageInfo.getTotal(),voList);
    }

    /**
     * 查询订单状态数量
     * @return
     */
    @Override
    public OrderStatisticsVO statistics() {
        //查询待派送的订单数量
        Integer confirmed = ordersMapper.countByStatus(Orders.CONFIRMED);
        //查询派送中的订单数量
        Integer deliveryInProgress = ordersMapper.countByStatus(Orders.DELIVERY_IN_PROGRESS);
        //查询待接单的订单数量
        Integer toBeConfirmed = ordersMapper.countByStatus(Orders.TO_BE_CONFIRMED);
        return new OrderStatisticsVO(toBeConfirmed,confirmed,deliveryInProgress);
    }

    /**
     * 管理端取消订单
     * @param ordersCancelDTO
     */
    @Override
    public void adminCancel(OrdersCancelDTO ordersCancelDTO) {
        Orders dbOrders = ordersMapper.findById(ordersCancelDTO.getId());
        if (dbOrders.getPayStatus() == Orders.PAID){
            /* 如果已经付款了,要通知微信端退款 */
        }
        Orders orders = new Orders();
        //设置订单id
        orders.setId(ordersCancelDTO.getId());
        //设置取消订单原因
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        //订单状态改为已取消
        orders.setStatus(Orders.CANCELLED);
        //设置取消时间
        orders.setCancelTime(LocalDateTime.now());
        ordersMapper.update(orders);
    }

    /**
     * 拒绝订单
     * @param ordersRejectionDTO
     */
    @Override
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        Orders orders = Orders.builder()
                //订单id
                .id(ordersRejectionDTO.getId())
                //拒绝原因
                .rejectionReason(ordersRejectionDTO.getRejectionReason())
                //取消时间
                .cancelTime(LocalDateTime.now())
                //该状态为取消
                .status(Orders.CANCELLED)
                .build();
        /* 这里拒单之后要通知微信端退款 */
        ordersMapper.update(orders);
    }

    /**
     * 查询订单详情
     * @param id
     * @return
     */
    @Override
    public OrdersSearchVO details(Long id) {
        Orders orders = ordersMapper.findById(id);
        List<OrderDetail> list = orderDetailMapper.findByOrderId(id);
        OrdersSearchVO ordersSearchVO = new OrdersSearchVO();
        BeanUtils.copyProperties(orders, ordersSearchVO);
        String allDish = "";
        for (int i = 0; i < list.size(); i++) {
            //拼接菜品字符串
            String dish = list.get(i).getName();
            if (i == list.size() -1){
                allDish += dish;
            }else {
                allDish += dish + "，";
            }
        }
        ordersSearchVO.setOrderDishes(allDish);
        ordersSearchVO.setOrderDetailList(list);
        return ordersSearchVO;
    }

    /**
     * 管理端接单
     * @param ordersConfirmDTO
     */
    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = Orders.builder()
                .id(ordersConfirmDTO.getId())
                .status(Orders.CONFIRMED)
                .build();
        ordersMapper.update(orders);
    }

    /**
     * 管理端派送订单
     * @param id
     */
    @Override
    public void delivery(Long id) {
        Orders orders = Orders.builder()
                .id(id)
                //改成派送中状态
                .status(Orders.DELIVERY_IN_PROGRESS)
                .build();
        ordersMapper.update(orders);
    }

    /**
     * 管理端完成订单
     * @param id
     */
    @Override
    public void complete(Long id) {
        Orders orders = Orders.builder()
                .id(id)
                //改成已完成状态
                .status(Orders.COMPLETED)
                //设置送达时间
                .deliveryTime(LocalDateTime.now())
                .build();
        ordersMapper.update(orders);
    }
}
